#include <iostream>
#include <QException>
#include <QDebug>
#include <QPolygon>
#include <QFileDialog>
#include <QMessageBox>
#include <vector>
#include "widget.h"
#include "ui_widget.h"
using namespace std;

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(750, 440);
    this->setFixedSize(750, 440);
    this->setPalette(Qt::yellow);
    this->setWindowTitle("Draw figures");

    scene = new Scene();
    ui->graphicsView->setScene(scene);
    ui->graphicsView->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
    scene->setSceneRect(0, 0, 620, 360);

    ui->graphicsView->setRenderHint(QPainter::Antialiasing);
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    ui->Draw->setChecked(true);
    ui->Extension->setChecked(true);
    ui->ChoseChange->setEnabled(false);
    ui->Ellipse->setChecked(true);
    ui->Extension->setChecked(true);
    ui->ClearScene->setEnabled(false);
    ui->SaveInFile->setEnabled(false);

    connect(ui->FillFromFile, &QPushButton::clicked, this, &Widget::slotFillFromFile);
    connect(ui->SaveInFile, &QPushButton::clicked, this, &Widget::slotSaveInFile);

    connect(ui->Ellipse, &QRadioButton::clicked, scene, &Scene::slotEllipseState);
    connect(ui->Rectangle, &QRadioButton::clicked, scene, &Scene::slotRectangleState);
    connect(ui->Triangle, &QRadioButton::clicked, scene, &Scene::slotTriangleState);

    connect(ui->Draw, &QRadioButton::clicked, this, &Widget::slotEnableDraw);
    connect(ui->Select, &QRadioButton::clicked, this, &Widget::slotEnableSelect);
    connect(ui->Change, &QRadioButton::clicked, this, &Widget::slotEnableChange);

    connect(scene, &Scene::signalGetNewFigure, this, &Widget::slotAddNewFigure);
    connect(scene, &Scene::signalGetSelectionFigures, this, &Widget::slotSelection);

    connect(ui->Extension, &QRadioButton::clicked, scene, &Scene::slotExtension);
    connect(ui->Shift, &QRadioButton::clicked, scene, &Scene::slotShift);
    connect(ui->Turn, &QRadioButton::clicked, scene, &Scene::slotTurn);

    connect(scene, &Scene::signalGetCoef, this, &Widget::slotChangeFigure);

    connect(ui->ClearScene, &QPushButton::clicked, this, &Widget::slotClearScene);
    connect(ui->ClearScene, &QPushButton::clicked, this, &Widget::slotEnableDraw);
}

Widget::~Widget()
{
    delete ui;
    delete scene;
}

void Widget::turnFigure(QGraphicsItem *fig, QPoint centralPoint, double angle)
{
    fig->setTransformOriginPoint(centralPoint);
    fig->setRotation(angle);
}

QGraphicsItem* Widget::addFigureToScene(FigureType figType, vector<double> figure, pair<double, double> centre)
{
    qDebug() << "OK";
    QGraphicsItem *fig;
    switch (figType) {
        case ell:
            qDebug() << "ell";
            for (int i = 0; i < 5; ++i) {
                qDebug() << figure[i];
            }
            fig = scene->addEllipse(figure[0], figure[1], figure[2], figure[3],
                QPen(Qt::green, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin),
                QBrush(Qt::blue));
            turnFigure(fig, QPoint(centre.first, centre.second), figure[4]);
        break;

        case FigureType::rect:
            qDebug() << "rect";
            fig = scene->addRect(figure[0], figure[1], figure[2], figure[3],
                    QPen(Qt::yellow, 3, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin),
                    QBrush(Qt::red));
            turnFigure(fig, QPoint(centre.first, centre.second), figure[4]);
        break;

        case tri:
            qDebug() << "tri";
            QPolygon triangle;
            triangle << QPoint(figure[0], figure[1]) << QPoint(figure[2], figure[3]) << QPoint(figure[4], figure[5]);
            fig = scene->addPolygon(triangle,
                    QPen(Qt::magenta, 3, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin),
                    QBrush(Qt::white));

            turnFigure(fig, QPoint(centre.first, centre.second), figure[6]);
        break;
    }

    return fig;
}

void Widget::slotFillFromFile()
{
    size_t firstIndexNewFigures = fg.size();

    try {
        ui->FillFromFile->setEnabled(false);

        QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Figures (*.txt)"));
        qDebug() << fileName;

        if (fileName != "") {
            fg.inputFile(fileName.toStdString());

            for (size_t i = firstIndexNewFigures; i < fg.size(); ++i) {
                qDebug() << i;
                vector<double> figure = fg[i]->getData();
                QGraphicsItem* fig = addFigureToScene(fg[i]->type(), figure, fg[i]->getCentrePoint());
                ptrfg[fig] = i;
                qDebug() << ptrfg[fig];
                fig->setFlag(QGraphicsItem::ItemIsSelectable);
            }
        }
    }
    catch(QException& e) {
        qDebug() << "exception caught: " << e.what();
    }

    ui->FillFromFile->setEnabled(true);

    qDebug() << "fg.size()" << fg.size() << firstIndexNewFigures + 1;
    if (firstIndexNewFigures + 1 == fg.size()) {
        vector<double> figure = {0, 0, 0, 0, 0};
        if (fg[firstIndexNewFigures]->getData() == figure) {
            fg.remove(firstIndexNewFigures);
            QMessageBox::warning(this, tr("Warning!"), tr("Your file is empty!"));
        }
    }
    qDebug() << "fg.size()" << fg.size();

    if (fg.size() > firstIndexNewFigures) {
        ui->ClearScene->setEnabled(true);
        ui->SaveInFile->setEnabled(true);
    }
}

void Widget::slotSaveInFile()
{
    ui->SaveInFile->setEnabled(false);

    for (size_t i = 0; i < fg.size(); ++i) {
        qDebug() << fg.size() << fg[i]->type();
    }

    try {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Figures (*.txt)"));
        if (fileName != "") {
            fg.outputFile(fileName.toStdString());
        }
    }
    catch(exception& e) {
        cout << "exception caught: " << e.what() << endl;
    }

    ui->SaveInFile->setEnabled(true);
}

void Widget::slotEnableDraw()
{
    scene->actionType = 'd';   
    ui->ChoseFigure->setEnabled(true);
    ui->ChoseChange->setEnabled(false);
}

void Widget::slotEnableSelect()
{
    scene->actionType = 's';
    ui->ChoseFigure->setEnabled(false);
    ui->ChoseChange->setEnabled(false);
}

void Widget::slotEnableChange()
{
    scene->actionType = 'c';
    ui->ChoseFigure->setEnabled(false);
    ui->ChoseChange->setEnabled(true);
}

void Widget::slotAddNewFigure(vector<double> data, QGraphicsItem *ptr)
{
    ui->ClearScene->setEnabled(true);
    ui->SaveInFile->setEnabled(true);

    FigureType type;

    if (scene->figureType == 'e') type = ell;
    if (scene->figureType == 'r') type = FigureType::rect;
    if (scene->figureType == 't') type = tri;

    fg.addFigure(type, data);
    ptrfg[ptr] = fg.size() - 1;
    qDebug() << ptrfg[ptr];
}

void Widget::slotSelection(QList<QGraphicsItem *> data)
{
    qDebug() << "slotSelection";
    selectionFigures.clear();
    for (int i = 1; i < data.size(); ++i) {
        if (data[i]->isSelected()) {
            qDebug() << ptrfg[data[i]] << data[i];
            data[i]->setEnabled(true);
            selectionFigures.push_back(ptrfg[data[i]]);
        }
    }
}

void Widget::changeFigureToScene(FigureType figType, QGraphicsItem *fig,
                                 vector<double> figure, pair<double, double> centre)
{
    for (size_t i = 0; i < figure.size(); ++i) {
        qDebug() << figure[i];
    }

    switch (figType) {
        case ell:
            qDebug() << figType;
            (static_cast<QGraphicsEllipseItem*>(fig))->setRect(figure[0], figure[1], figure[2], figure[3]);
            turnFigure(fig, QPoint(centre.first, centre.second), figure[4]);
        break;
        case FigureType::rect:
            qDebug() << figType;
            (static_cast<QGraphicsRectItem*>(fig))->setRect(figure[0], figure[1], figure[2], figure[3]);
            turnFigure(fig, QPoint(centre.first, centre.second), figure[4]);
        break;
        case tri:
            QPolygon triangle;
            triangle << QPoint(figure[0], figure[1]) << QPoint(figure[2], figure[3]) << QPoint(figure[4], figure[5]);
            (static_cast<QGraphicsPolygonItem*>(fig))->setPolygon(triangle);
            turnFigure(fig, QPoint(centre.first, centre.second), figure[6]);
        break;
    }
}

void Widget::slotChangeFigure(pair<double, double> coef) {
    double currentCoef = sqrt(coef.first * coef.first + coef.second * coef.second);
    switch (scene->changeFigureType) {
        case 'e':
            (currentCoef / 20 < 1) ? currentCoef = 1 : currentCoef /= 20;
            if ((coef.first < 0 && coef.second < 0) || (coef.first < 0 && coef.second > 0)) {
                currentCoef = 1 / currentCoef;
            }
            for (int i = 0; i < selectionFigures.size(); ++i) {
                fg[selectionFigures[i]]->extension(currentCoef);
                changeFigureToScene(fg[selectionFigures[i]]->type(),
                                    ptrfg.key(selectionFigures[i]),
                                    fg[selectionFigures[i]]->getData(),
                                    fg[selectionFigures[i]]->getCentrePoint());
            }
        break;

        case 's':
            qDebug() << "s  " << coef.first << " " << coef.second;
            for (int i = 0; i < selectionFigures.size(); ++i) {
                fg[selectionFigures[i]]->shift(coef.first, coef.second);
                changeFigureToScene(fg[selectionFigures[i]]->type(),
                                    ptrfg.key(selectionFigures[i]),
                                    fg[selectionFigures[i]]->getData(),
                                    fg[selectionFigures[i]]->getCentrePoint());
            }
        break;

        case 't':
            qDebug() << "t  " << currentCoef;
            for (int i = 0; i < selectionFigures.size(); ++i) {
                fg[selectionFigures[i]]->turn(currentCoef);
                changeFigureToScene(fg[selectionFigures[i]]->type(),
                                    ptrfg.key(selectionFigures[i]),
                                    fg[selectionFigures[i]]->getData(),
                                    fg[selectionFigures[i]]->getCentrePoint());
            }
        break;
    }
}

void Widget::slotClearScene()
{
    scene->clear();
    fg.removeAll();
    ptrfg.clear();
    selectionFigures.clear();

    ui->Draw->setChecked(true);
    ui->ClearScene->setEnabled(false);
    ui->SaveInFile->setEnabled(false);
}
